﻿using System;
using System.IO;
using Microsoft.SharePoint;

namespace Lapointe.WebPartPageHistory.ListEventReceivers
{
    public class SourceListEventReceiver : SPItemEventReceiver
    {

        /// <summary>
        /// Synchronous before event that occurs when an existing item is changed, for example, when the user changes data in one or more fields.
        /// </summary>
        /// <param name="properties">An <see cref="T:Microsoft.SharePoint.SPItemEventProperties"></see> object that represents properties of the event handler.</param>
        public override void ItemUpdating(SPItemEventProperties properties)
        {
            // TODO: see if we can remove the tagging hack and use a long running job definition to do the import.
            DisableEventFiring();
            try
            {
                SPListItem sourceItem = properties.ListItem;
                if (sourceItem == null || sourceItem.File == null)
                    return;

                if (!sourceItem.File.Name.ToLowerInvariant().EndsWith(".aspx"))
                    return;

                // If the VersionID is null or empty then we don't have a saved version so exit.
                if (properties.AfterProperties[HistoryHelper.PROP_VERSIONID_KEY] == null ||
                    properties.AfterProperties[HistoryHelper.PROP_VERSIONID_KEY].ToString() == string.Empty)
                    return;

                // If the updated VersionID does not match the current VersionID then adjust the ID to flag
                // to the ItemUpdated event that we need to do a restore.
                if (properties.AfterProperties[HistoryHelper.PROP_VERSIONID_KEY].ToString() !=
                    sourceItem.Properties[HistoryHelper.PROP_VERSIONID_KEY].ToString())
                    properties.AfterProperties["VersionID"] = "RESTORE_" + properties.AfterProperties["VersionID"];
            }
            finally
            {
                EnableEventFiring();
            }
        }

        /// <summary>
        /// Asynchronous after event that occurs after an existing item is changed, for example, when the user changes data in one or more fields.
        /// </summary>
        /// <param name="properties">An <see cref="T:Microsoft.SharePoint.SPItemEventProperties"></see> object that represents properties of the event handler.</param>
        public override void ItemUpdated(SPItemEventProperties properties)
        {
            DisableEventFiring();
            try
            {
                SPListItem sourceItem = properties.ListItem;
                if (sourceItem == null || sourceItem.File == null)
                    return;

                if (!sourceItem.File.Name.ToLowerInvariant().EndsWith(".aspx"))
                    return;
                
                // If the VersionID does not have the "RESTORE_" marker then it's a simple update and not a restore so exit.
                if (!properties.ListItem.Properties[HistoryHelper.PROP_VERSIONID_KEY].ToString().StartsWith("RESTORE_"))
                    return;

                // We're doing a restore so get the list item and restore key.
                string restoreKey = sourceItem.Properties[HistoryHelper.PROP_VERSIONID_KEY].ToString().Replace("RESTORE_", "");

                SPSecurity.RunWithElevatedPrivileges(
                    delegate
                        {
                            // Get the exported item from the history list.
                            SPListItem historyItem = HistoryHelper.GetHistoryItem(properties.SiteId, properties.RelativeWebUrl, sourceItem, restoreKey);

                            if (historyItem == null)
                            {
                                // Couldn't find a historical item so fix the VersionID and exit
                                sourceItem.Properties[HistoryHelper.PROP_VERSIONID_KEY] = restoreKey;
                                sourceItem.SystemUpdate(false);
                                return;
                            }

                            string directory = HistoryHelper.GetTempDirectory();

                            // Unzip the history item to a temporary location for the import.
                            CommonUtilities.UnZipFile(historyItem, directory);

                            // Get the method in which the item was exported via the history item properties.
                            HistoryMethod method = HistoryHelper.GetHistoryMethod(historyItem);

                            // Import the exported item.
                            HistoryFactory.GetHistoryObject(method).Import(sourceItem, directory);

                            // Cleanup temporary files.
                            Directory.Delete(directory, true);

                        });
            }
            finally
            {
                EnableEventFiring();
            }
        }


        /// <summary>
        /// Asynchronous after event that occurs after an item is checked in.
        /// </summary>
        /// <param name="properties">An <see cref="T:Microsoft.SharePoint.SPItemEventProperties"></see> object that represents properties of the event handler.</param>
        public override void ItemCheckedIn(SPItemEventProperties properties)
        {
            DisableEventFiring();
            try
            {
                SPListItem sourceItem = properties.ListItem;
                if (sourceItem == null || sourceItem.File == null)
                    return;

                if (!sourceItem.File.Name.ToLowerInvariant().EndsWith(".aspx"))
                    return;

                // We've created a new version so update the VersionID property with a new GUID.
                sourceItem.Properties[HistoryHelper.PROP_VERSIONID_KEY] = Guid.NewGuid().ToString();
                sourceItem.SystemUpdate(false);

                string directory = HistoryHelper.GetTempDirectory();
                
                SPSecurity.RunWithElevatedPrivileges(
                    delegate
                        {
                            // Get the history method and dependency setting from the list settings
                            HistoryMethod method = HistoryHelper.GetHistoryMethod(sourceItem.ParentList);
                            bool includeDependencies = HistoryHelper.IncludeDependencies(sourceItem.ParentList);

                            // Export the item to the specified directory.
                            HistoryFactory.GetHistoryObject(method).Export(sourceItem, directory, includeDependencies);
                            
                            // Zip up exported files.
                            CommonUtilities.ZipFiles(directory);

                            // Add the exported data to the history list.
                            HistoryHelper.AddHistoryItem(sourceItem, method, Path.Combine(directory, "item.zip"), properties.SiteId, properties.RelativeWebUrl);
                            
                            // Cleanup temp files.
                            Directory.Delete(directory, true);
                        });
            }
            finally
            {
                EnableEventFiring();
            }
        }

        
    }
}
